﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using Lenic.DI.Lifetimes;

namespace Lenic.DI.Drivers
{
    [DebuggerStepThrough]
    internal class DefaultStore : IStore
    {
        #region Private Fields

        private readonly IDictionary<Type, ServiceValue> data = null;

        #endregion Private Fields

        #region Entrance

        public DefaultStore()
        {
            data = new Dictionary<Type, ServiceValue>();
        }

        #endregion Entrance

        #region ServiceValue

        private class ServiceValue
        {
            public ServiceValue()
            {
                NamedValues = new Dictionary<string, ILifetime>();
            }

            public IDictionary<string, ILifetime> NamedValues { get; set; }

            public ILifetime NullNamedValue { get; set; }
        }

        #endregion ServiceValue

        #region IDisposable 成员

        public void Dispose()
        {
            foreach (var item in this)
            {
                if (item != null)
                    item.Dispose();
            }
            GC.SuppressFinalize(data);
        }

        #endregion IDisposable 成员

        #region IEnumerable<ILifetime> 成员

        public IEnumerator<ILifetime> GetEnumerator()
        {
            foreach (var item in data.Values)
            {
                yield return item.NullNamedValue;
                foreach (var innerItem in item.NamedValues.Values)
                    yield return innerItem;
            }
        }

        #endregion IEnumerable<ILifetime> 成员

        #region IEnumerable 成员

        IEnumerator IEnumerable.GetEnumerator()
        {
            return this.GetEnumerator();
        }

        #endregion IEnumerable 成员

        #region IStore 成员

        public void Add(Type serviceType, string name, ILifetime value)
        {
            ServiceValue values = null;
            bool exists = data.TryGetValue(serviceType, out values);
            if (!exists)
                values = new ServiceValue();

            if (name == null)
            {
                values.NullNamedValue = value;
            }
            else
                values.NamedValues[name] = value;

            if (!exists)
                data[serviceType] = values;
        }

        public IEnumerable<ILifetime> GetValues(Type type)
        {
            ServiceValue values;
            if (data.TryGetValue(type, out values))
            {
                if (values.NullNamedValue != null)
                    yield return values.NullNamedValue;

                foreach (var item in values.NamedValues.Values)
                    yield return item;
            }
        }

        public bool TryGetValue(Type serviceType, string name, out ILifetime value)
        {
            ServiceValue values = null;
            value = null;
            if (data.TryGetValue(serviceType, out values))
            {
                if (name == null)
                    return (value = values.NullNamedValue) != null;
                else
                    return values.NamedValues.TryGetValue(name, out value);
            }
            return false;
        }

        #endregion IStore 成员
    }
}